/* 
 * File:   dbhelper.cpp
 * Author: anand
 * 
 */
#include "dbhelper.h"


dbhelper::dbhelper(): //This doesnt look good ://
playlist_table( new table(PLAYLIST_TABLE_NAME, PLAYLIST_TABLE_CREATION_SQL))
,playlistitem_table(new table(PLAYLISTITEM_TABLE_NAME, PLAYLISTITEM_TABLE_CREATION_SQL))
,playlistitems_table(new table(PLAYLISTITEMS_TABLE_NAME, PLAYLISTITEMS_TABLE_CREATION_SQL))
,folder_table(new table(FOLDER_TABLE_NAME, FOLDER_CREATION_SQL))
 {
	char *dbname = new char[256];
	*dbname='\0';
	strcat(dbname,strdup(path_util::get_home_dir()));
	strcat(dbname,DBNAME);
    connect(dbname);
	delete dbname;

}

dbhelper * dbhelper::get_helper() {
    static dbhelper helper;
    return &helper;
}

void dbhelper::connect(char * dbName) {
    int rc = sqlite3_open(dbName, &_db);
    if (rc != SQLITE_OK) {
        log_util::log_debug("Error connecting to %s\n", dbName);
    }

    init_db();
}

void dbhelper::init_db() {
    if (!table_exists(playlist_table)) {
        table_create(playlist_table);
    }
    if (!table_exists(folder_table)) {
		table_create(folder_table);
    }
    if (!table_exists(playlistitem_table)) {
        table_create(playlistitem_table);
    }
    if (!table_exists(playlistitems_table)) {
        table_create(playlistitems_table);
    }
}

int dbhelper::raw_execute(const char* sql) {
    sqlite3_stmt *ppStmt;
    const char *pzTail;
    int rc = sqlite3_prepare_v2(_db, sql, strlen(sql), &ppStmt, &pzTail);
    if (rc != SQLITE_OK) {
        log_util::log_debug("Unable to prepare statement for: %s\n", sql);
        return rc;
    }

    log_util::log_debug( "Executed sql: %s\n", sql);

    rc = sqlite3_step(ppStmt);
    while (rc == SQLITE_ROW) {
        for (int i = 0; i < sqlite3_column_count(ppStmt); ++i) {
            const char * columnName = sqlite3_column_name(ppStmt, i);
            const unsigned char * columnData = sqlite3_column_text(ppStmt, i);
            log_util::log_debug( "%s=%s\n", columnName, columnData);
        }
        log_util::log_debug("\n");
        rc = sqlite3_step(ppStmt);
    }

    //NOTE: sqlite3_bind (?) fill in vals for these params
    //NOTE: can use sqlite3_reset()=> sqlite3_bind() to enter new params

    sqlite3_finalize(ppStmt);
    return SQLITE_OK;
}

result_set * dbhelper::get_row_map(const char *sql){
    sqlite3_stmt *ppStmt;
    const char *pzTail;
    std::vector< std::map<std::string,std::string> * > * rvector = new std::vector< std::map<std::string,std::string>* >;
    int rc = sqlite3_prepare_v2(_db, sql, strlen(sql), &ppStmt, &pzTail);
    if (rc != SQLITE_OK) {
        log_util::log_debug("Unable to prepare statement for: %s\n", sql);
        return rvector;
    }

    log_util::log_debug("Executed sql: %s\n", sql);


    rc = sqlite3_step(ppStmt);
    while (rc == SQLITE_ROW) {
        std::map<std::string,std::string> * row = 0;
        for (int i = 0; i < sqlite3_column_count(ppStmt); ++i) {
            const char * columnName = sqlite3_column_name(ppStmt, i);
            const unsigned char * columnData = sqlite3_column_text(ppStmt, i);
			if(columnName && columnData) //shouldnt be null
			{
				if(!row) 
					row = new  std::map<std::string,std::string>;
				(*row)[strdup(columnName)] = strdup((const char *)columnData);
			}
        }
		if(row)
			rvector->push_back(row);
        rc = sqlite3_step(ppStmt);
    }

    sqlite3_finalize(ppStmt);
    return rvector;
}

bool dbhelper::table_exists(table *table_) {
	log_util::log_debug("Checking table: %s...", table_->name());
    char *preSQL = "SELECT * FROM ";
    char *testSQL = new char[strlen(preSQL) + strlen(table_->name()) + 1];
    sprintf(testSQL, "%s%s", preSQL, table_->name());
    sqlite3_stmt *ppStmt;
    const char *pzTail;
    int rc = sqlite3_prepare_v2(_db, testSQL, strlen(testSQL), &ppStmt, &pzTail);
    delete [] testSQL;
    sqlite3_finalize(ppStmt);
    if (rc != SQLITE_OK) {
        log_util::log_debug( "%s DOESNOT EXISTS\n", table_->name());
        return false;
    } else {
        log_util::log_debug("%s EXISTS\n", table_->name());
        return true;
    }

}

void dbhelper::table_create(table *table_) {
	log_util::log_debug("Creating table %s\n", table_->name());
    raw_execute(table_->creation_sql());
}

int dbhelper::get_id(const char * table_name){
	std::string sql = GET_NEW_ID_SQL;
	sql.replace(sql.find("?"),1,table_name);
	result_set * result = get_row_map(sql.c_str());
	if(result->size() != 0)
		return atoi((*(result->at(0)))["id"].c_str());
	else
		return 1;
}

dbhelper::~dbhelper() {
    log_util::log_debug("Closing DB Connection\n");
    sqlite3_close(_db);
    _db = 0;
}

